#include <linux/sched/task_types.h>
#include <linux/sched/task.h>
#include <linux/thread_info.h>
#include <asm/processor.h>
#include <linux/sched/task_stack.h>
#include <asm/ptrace.h>
#include <uapi/asm/ptrace.h>
#include <linux/preempt.h>
#include <linux/printk.h>
#include <arm/v7m.h>
#include <asm/io.h>
#include <linux/string.h>
#include <linux/math.h>

struct task_struct *__current = &init_task;

struct task_struct *get_current(void)
{
    return __current;
}

void set_current(struct task_struct *p)
{
    __current = p;
}

struct pt_regs *task_pt_regs(struct task_struct *p)
{
    struct pt_regs *regs;

    regs = (struct pt_regs *)(THREAD_START_SP + (unsigned long)task_stack_page(p));

    regs--;

    return regs;
}

int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
{
    struct thread_info *thread = task_thread_info(p);
    struct pt_regs *childregs = task_pt_regs(p);

    memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));

    if (!args->fn)
    {
    }
    else
    {
        memset(childregs, 0, sizeof(struct pt_regs));
        thread->cpu_context.r4 = (unsigned long)args->fn_arg;
        thread->cpu_context.r5 = (unsigned long)args->fn;

        childregs->hwsave.r0 = args->fn_arg;
        childregs->hwsave.pc = args->fn;
        childregs->hwsave.psr = 0x01000000;
        childregs->exc_return = 0xffffffe1 | EXC_RET_THREADMODE_PROCESSSTACK;
    }

    thread->cpu_context.sp = childregs;

    return 0;
}

void init_thread_info(struct task_struct *p)
{
    struct thread_info *ti = task_thread_info(p);

    ti->flags = 0;
    ti->preempt.preempt = INIT_PREEMPT_COUNT;
}
